#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""MySQLPass独立可执行程序打包脚本
用于将mysqlpass项目打包成一个可独立运行的exe程序
"""

import os
import sys
import subprocess
import shutil
import platform
from datetime import datetime

# 确保脚本在正确的目录下运行
script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir)

# 定义项目相关路径
PROJECT_NAME = "mysqlpass"
MAIN_SCRIPT = "main.py"
OUTPUT_DIR = os.path.join("dist")
REQUIREMENTS_FILE = "requirements_utf8.txt"

# 定义打包参数
BUILD_NAME = "MySQLPass"
BUILD_VERSION = "1.0.0"


def check_and_install_dependencies():
    """检查并安装必要的依赖"""
    print("正在检查并安装必要的依赖...")
    
    # 检查PyInstaller是否已安装
    try:
        subprocess.run([sys.executable, "-m", "PyInstaller", "--version"], 
                      check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        print("PyInstaller已安装")
    except (subprocess.CalledProcessError, FileNotFoundError):
        print("正在安装PyInstaller...")
        try:
            subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"], 
                          check=True)
            print("PyInstaller安装成功")
        except subprocess.CalledProcessError:
            print("PyInstaller安装失败")
            return False
    
    # 直接安装项目依赖，避免requirements文件编码问题
    print("正在安装项目依赖...")
    dependencies = [
        "pymysql==1.0.3",
        "cryptography==41.0.3",
        "click==8.1.7",
        "prettytable==3.8.0",
        "pandas==2.2.0",
        "openpyxl==3.1.2",
        "xlwt==1.3.0",
        "requests==2.31.0"
    ]
    
    for dep in dependencies:
        print(f"安装: {dep}")
        try:
            subprocess.run([sys.executable, "-m", "pip", "install", dep], 
                          check=True)
        except subprocess.CalledProcessError as e:
            print(f"安装{dep}失败: {e}")
            return False
    
    print("所有项目依赖安装成功")
    
    return True


def clean_build_dir():
    """清理之前的构建文件"""
    print("清理之前的构建文件...")
    
    # 清理PyInstaller生成的目录
    for dir_name in ["build", "dist"]:
        dir_path = os.path.join(script_dir, dir_name)
        if os.path.exists(dir_path):
            try:
                shutil.rmtree(dir_path)
                print(f"已清理目录: {dir_name}")
            except Exception as e:
                print(f"清理目录失败 {dir_name}: {e}")
    
    # 清理spec文件
    for file in os.listdir(script_dir):
        if file.endswith(".spec"):
            try:
                os.remove(os.path.join(script_dir, file))
                print(f"已清理spec文件: {file}")
            except Exception as e:
                print(f"清理spec文件失败 {file}: {e}")


def create_version_info_file():
    """创建版本信息文件"""
    # 预先处理版本号
    major, minor, patch = BUILD_VERSION.split('.')
    current_year = datetime.now().year
    
    # 使用字符串format方法，将花括号转义为双花括号
    version_info_content = """
VSVersionInfo({{
  'ffi': {{'ffiwValue': 16777216}},
  'mask': 0x3f,
  'os': 0x40004,
  'filevers': ({0}, {1}, {2}, 0),
  'prodvers': ({0}, {1}, {2}, 0),
  'pszOSVerName': 'Windows NT',
  'pszFileDesc': 'MySQLPass - 自由使用的MySQL工具',
  'pszInternalName': 'MySQLPass',
  'pszOriginalFilename': 'MySQLPass.exe',
  'pszProductName': 'MySQLPass',
  'pszCompanyName': 'MySQLPass Team',
  'pszLegalCopyright': '© {3} MySQLPass. All rights reserved.',
  'pszLegalTrademarks': '',
  'pszComments': '安全、便捷的MySQL密码管理解决方案'
}}
)
"""
    
    # 应用format方法填充占位符
    version_info_content = version_info_content.format(major, minor, patch, current_year)
    
    version_info_path = "version_info.txt"
    with open(version_info_path, "w", encoding="utf-8") as f:
        f.write(version_info_content)
    
    print(f"已创建版本信息文件: {version_info_path}")
    return version_info_path


def build_with_pyinstaller():
    """使用PyInstaller打包应用"""
    print(f"开始打包{PROJECT_NAME}项目为独立可执行程序...")
    
    # 创建版本信息文件
    version_info_path = create_version_info_file()
    
    # 构建PyInstaller命令参数
    cmd = [
        sys.executable,
        "-m",
        "PyInstaller",
        "--name", BUILD_NAME,
        "--windowed",  # 不显示控制台窗口
        "--icon", os.path.join("src", "data", "mp.png"),  # 使用mp.png作为图标
        "--version-file", version_info_path,
        "--collect-all", "pymysql",  # 收集所有pymysql依赖
        "--collect-all", "cryptography",  # 收集所有cryptography依赖
        "--collect-all", "click",  # 收集所有click依赖
        "--collect-all", "prettytable",  # 收集所有prettytable依赖
        "--collect-all", "pandas",  # 收集所有pandas依赖
        "--collect-all", "openpyxl",  # 收集所有openpyxl依赖
        "--collect-all", "xlwt",  # 收集所有xlwt依赖
        "--collect-all", "requests",  # 收集所有requests依赖
        "--add-data", f"src{os.pathsep}src",  # 添加源代码目录
        "--add-data", f"README.md{os.pathsep}.",  # 添加README文件
        "--add-data", f"README.en.md{os.pathsep}.",  # 添加英文README文件
        "--noupx",  # 禁用UPX压缩，避免DLL问题
        "--onefile"  # 打包成单个可执行文件
    ]
    
    # 如果需要包含updates目录
    if os.path.exists("updates"):
        cmd.extend(["--add-data", f"updates{os.pathsep}updates"])
    
    # 添加主脚本
    cmd.append(MAIN_SCRIPT)
    
    # 执行打包命令
    try:
        print(f"执行打包命令: {' '.join(cmd)}")
        subprocess.run(cmd, check=True)
        print("打包成功")
        return True
    except subprocess.CalledProcessError as e:
        print(f"打包失败: {e}")
        return False
    except Exception as e:
        print(f"打包过程中发生未知错误: {e}")
        return False


def verify_build():
    """验证打包结果"""
    exe_path = os.path.join(OUTPUT_DIR, f"{BUILD_NAME}.exe")
    if os.path.exists(exe_path):
        print(f"\n=== 打包完成 ===")
        print(f"独立可执行文件已生成: {exe_path}")
        print(f"文件大小: {os.path.getsize(exe_path) / 1024 / 1024:.2f} MB")
        print("\n可以直接运行该exe文件，无需安装Python环境")
        return True
    else:
        print(f"打包失败: 未找到生成的可执行文件 {exe_path}")
        return False


def main():
    """主函数"""
    print("=====================================")
    print(f"MySQLPass v{BUILD_VERSION} 独立可执行程序打包工具")
    print("=====================================")
    
    # 检查系统环境
    if platform.system() != "Windows":
        print("警告: 此脚本主要为Windows系统设计")
    
    # 检查并安装依赖
    if not check_and_install_dependencies():
        print("依赖安装失败，无法继续打包")
        sys.exit(1)
    
    # 清理之前的构建文件
    clean_build_dir()
    
    # 开始打包
    if build_with_pyinstaller():
        # 验证打包结果
        verify_build()
    else:
        print("打包失败，请检查错误信息")
        sys.exit(1)


if __name__ == "__main__":
    main()